//
//  Me2DayAttach.m
//  CairnStory
//  www.cairnstory.com
//
//  Created by saturna on 11. 3. 18..
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Me2DayRequest.h"
#import "Me2DayRequestDelegate.h"
#import "Me2DayOAuthResult.h"
#import "Me2DayAttach.h"
#import "Me2DayUtil.h"
#import "NSString+URLEncoding.h"
#import "NSString+MD5.h"
#import "JSON.h"

#pragma mark -
#pragma mark Me2DayRequest (PrivateMethods)

@interface Me2DayRequest (PrivateMethods)

- (NSString*)requestURLStringWithMethodName:(NSString*)methodName;

- (void)requestWithURLString:(NSString*)urlString
				   andParams:(NSMutableDictionary*)params
			   andHttpMethod:(NSString*)httpMethod;

- (void)multipartRequestWithURLString:(NSString*)urlString
							andParams:(NSMutableDictionary*)params;

- (void)appendParamToBodyData:(NSMutableData*)postBodyData
					   andKey:(NSString*)key
					 andValue:(NSString*)value;

- (void)appendAttachToBodyData:(NSMutableData*)postBodyData
						andKey:(NSString*)key
					 andAttach:(Me2DayAttach*)attach;

- (void)failMessage:(NSString*)message
		   andError:(NSError*)error;

- (void)connectWithRequest:(NSURLRequest*)request;

@end


#pragma mark -
#pragma mark constants define

NSString* const Me2DayRequestMethodCreatePost = @"create_post";
NSString* const Me2DayRequestMethodGetPosts = @"get_posts";
NSString* const Me2DayRequestMethodDeletePost = @"delete_post";
//NSString* const Me2DayRequestMethodGetTags = @"get_tags";


NSString* const Me2DayRequestMethodCreateComment = @"create_comment";
NSString* const Me2DayRequestMethodGetComments = @"get_comments";
NSString* const Me2DayRequestMethodDeleteComment = @"delete_comment";
NSString* const Me2DayRequestMethodTrackComments = @"track_comments";

NSString* const Me2DayRequestMethodMeToo = @"metoo";
NSString* const Me2DayRequestMethodGetMeToos = @"get_metoos";

NSString* const Me2DayRequestMethodGetFriendshipRequests = @"get_friendship_requests";
NSString* const Me2DayRequestMethodAcceptFriendshipRequest = @"accept_friendship_request";
NSString* const Me2DayRequestMethodGetFriends = @"get_friends";
NSString* const Me2DayRequestMethodFriendship = @"friendship";

NSString* const Me2DayRequestMethodGetPerson = @"get_person";
NSString* const Me2DayRequestMethodGetSettings = @"get_settings";

/*
글 관련 기능
 http://me2day.net/api/create_post/[미투데이아이디].[응답형식]
 http://me2day.net/api/get_posts.[응답형식]
 http://me2day.net/api/get_posts/[미투데이 사용자아이디].[응답형식]
 http://me2day.net/api/delete_post.[응답형식]
 http://me2day.net/api/get_tags.[응답형식]

댓글 관련 기능
 http://me2day.net/api/create_comment.[응답형식]
 http://me2day.net/api/get_comments/[사용자아이디].[응답형식]
 http://me2day.net/api/get_comments.[응답형식]
 http://me2day.net/api/delete_comment.[응답형식]
 http://me2day.net/api/track_comments/[미투데이아이디].[응답형식]

미투 관련 기능
 http://me2day.net/api/metoo.[응답형식]
 http://me2day.net/api/get_metoos.[응답형식]

친구 관련 기능
 http://me2day.net/api/get_friendship_requests/[미투데이아이디].[응답형식]
 http://me2day.net/api/accept_friendship_request.[응답형식]
 http://me2day.net/api/get_friends/[미투데이아이디].[응답형식]
 http://me2day.net/api/friendship.[응답형식]

사용자 정보 기능
 http://me2day.net/api/get_person/[미투데이아이디].[응답형식]
 http://me2day.net/api/get_settiings.[응답형식]

기타 기능
 http://me2day.net/api/noop.[응답형식]
 http://me2day.net/api/get_bands.[응답형식]

알리미 기능
 ...
글쓰기 링크 기능
 ...
*/
// method-name, user_id
#define kRequestURLFormat @"http://me2day.net/api/%@.json"
// method-name
#define kUserRequestURLFormat @"http://me2day.net/api/%@/%@.json"





#pragma mark -
#pragma mark Me2DayRequest

@implementation Me2DayRequest

@synthesize me2dayTag = m_me2dayTag;
@synthesize delegate = m_delegate;



#pragma mark -
#pragma mark init, dealloc

- (id)initWithMe2DayOAuthResult:(Me2DayOAuthResult*)oauth
{
	self = [super init];
	if (self == nil)
	{
		return self;
	}

	m_oauth = [oauth retain];

	return self;
}

- (void)dealloc
{
	[m_oauth release];
	if (m_responseData != nil)
	{
		[m_responseData release];
		m_responseData = nil;
	}
	[super dealloc];
}



#pragma mark -
#pragma mark request methods

- (void)requestWithMethodName:(NSString*)methodName
					andParams:(NSMutableDictionary*)params
				andHttpMethod:(NSString*)httpMethod
				 andMultipart:(BOOL)isMultipart
{
	[m_delegate me2dayRequest:self didStartWithTag:m_me2dayTag];

	NSString* urlString = [self requestURLStringWithMethodName:methodName];

	[params setObject:m_oauth.appKey forKey:@"akey"];
	[params setObject:m_oauth.userId forKey:@"uid"];
	[params setObject:[m_oauth generateUKey] forKey:@"ukey"];

	if (isMultipart)
	{
		[self multipartRequestWithURLString:urlString andParams:params];
	}
	else
	{
		[self requestWithURLString:urlString andParams:params andHttpMethod:httpMethod];
	}
}


- (void)requestWithMethodName:(NSString*)methodName
					andParams:(NSMutableDictionary*)params
				andHttpMethod:(NSString*)httpMethod
{
	[self requestWithMethodName:methodName
					  andParams:params
				  andHttpMethod:httpMethod
				   andMultipart:NO];
}

- (void)requestWithMethodName:(NSString*)methodName
					andParams:(NSMutableDictionary*)params
{
	[self requestWithMethodName:methodName
					  andParams:params
				  andHttpMethod:@"POST"
				   andMultipart:NO];
}




#pragma mark -
#pragma mark Me2DayRequest (PrivateMethods)

- (NSString*)requestURLStringWithMethodName:(NSString*)methodName
{
	if ([methodName isEqualToString:Me2DayRequestMethodCreatePost] ||
		[methodName isEqualToString:Me2DayRequestMethodTrackComments] ||
		[methodName isEqualToString:Me2DayRequestMethodGetFriendshipRequests] ||
		[methodName isEqualToString:Me2DayRequestMethodGetFriends] ||
		[methodName isEqualToString:Me2DayRequestMethodGetPerson])
	{
		return [NSString stringWithFormat:kUserRequestURLFormat, methodName, m_oauth.userId];
	}

	return [NSString stringWithFormat:kRequestURLFormat, methodName];
}

- (void)requestWithURLString:(NSString*)urlString
				   andParams:(NSMutableDictionary*)params
			   andHttpMethod:(NSString*)httpMethod
{
	NSURL* aURL = [[NSURL alloc] initWithString:urlString];
	NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:aURL];
	[aURL release];

	[urlRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
	[urlRequest setTimeoutInterval:kHTTPRequestTimeout];
	[urlRequest setHTTPMethod:httpMethod];

	[urlRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
	//[urlRequest setValue:m_oauth.appKey forHTTPHeaderField:@"me2_application_key"];

	NSMutableString* bodyString = [[NSMutableString alloc] init];
	NSArray* arrKey = [params allKeys];
	//if (DEBUG) Me2Log(@"===> aaa");
	for (int i=0; i<arrKey.count; i++)
	{
		//if (DEBUG) Me2Log(@"===> bbb");
		NSString* key = [arrKey objectAtIndex:i];
		NSObject* aValue = [params objectForKey:key];

		if ([aValue isKindOfClass:[NSArray class]])
		{
			//if (DEBUG) Me2Log(@"===> ccc");
			for (NSObject* obj in ((NSArray*)aValue))
			{
				if ([bodyString length] > 0)
				{
					[bodyString appendString:@"&"];
				}
				[bodyString appendFormat:@"%@=%@", key, [[obj description] URLEncodedString]];
			}
		}
		else
		{
			//if (DEBUG) Me2Log(@"===> ddd : %@ / %@", key, aValue);
			if ([bodyString length] > 0)
			{
				[bodyString appendString:@"&"];
			}
			[bodyString appendFormat:@"%@=%@", key, [[aValue description] URLEncodedString]];
		}
	}

	//if (DEBUG) Me2Log(@"===> eee : %@", bodyString);
	[urlRequest setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
	[bodyString release];

	[self connectWithRequest:[urlRequest autorelease]];
}



- (void)multipartRequestWithURLString:(NSString*)urlString
							andParams:(NSMutableDictionary*)params
{
	NSURL* aURL = [[NSURL alloc] initWithString:urlString];
	NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:aURL];
	[aURL release];

	[urlRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
	[urlRequest setTimeoutInterval:kHTTPRequestTimeout];
	[urlRequest setHTTPMethod:@"POST"];

	NSString* strContentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",
								kMultipartBoundarySuffix];
	[urlRequest setValue:strContentType forHTTPHeaderField:@"Content-Type"];
	//[urlRequest setValue:m_oauth.appKey forHTTPHeaderField:@"me2_application_key"];

	NSMutableData* bodyData = [[NSMutableData alloc] init];
	//if (DEBUG) Me2Log(@"===> aaa");

	NSArray* arrKey = [params allKeys];

	for (int i=0; i<arrKey.count; i++)
	{
		//if (DEBUG) Me2Log(@"===> bbb");
		NSString* key = [arrKey objectAtIndex:i];
		NSObject* aValue = [params objectForKey:key];

		if ([aValue isKindOfClass:[NSArray class]])
		{
			//if (DEBUG) Me2Log(@"===> ccc");
			NSArray* arrValue = (NSArray*)aValue;
			for (int k=0; k<arrValue.count; k++)
			{
				NSObject* obj = [arrValue objectAtIndex:k];
				if ([obj isKindOfClass:[Me2DayAttach class]])
				{
					//if (DEBUG) Me2Log(@"===> CSMultipartAttach[] : %@ = [%@]", key, obj);
					[self appendAttachToBodyData:bodyData
										  andKey:key
									   andAttach:(Me2DayAttach*)obj];
				}
				else
				{
					//if (DEBUG) Me2Log(@"===> String[] : %@ = [%@]", key, obj);
					[self appendParamToBodyData:bodyData
										 andKey:key
									   andValue:[obj description]];
				}
			}
		}
		else if ([aValue isKindOfClass:[Me2DayAttach class]])
		{
			//if (DEBUG) Me2Log(@"===> CSMultipartAttach : %@ = [%@]", key, aValue);
			[self appendAttachToBodyData:bodyData
								  andKey:key
							   andAttach:(Me2DayAttach*)aValue];
		}
		else
		{
			//if (DEBUG) Me2Log(@"===> String : %@ = [%@]", key, aValue);
			[self appendParamToBodyData:bodyData
								 andKey:key
							   andValue:[aValue description]];
		}
	}

	// terminating boundary
	if (arrKey.count > 0)
	{
		[bodyData appendData:[[NSString stringWithFormat:@"--%@--\r\n",
							   kMultipartBoundarySuffix] dataUsingEncoding:NSUTF8StringEncoding]];
	}

	NSString* bodyString = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];
	//if (DEBUG) Me2Log(@"===> bodyString : %d / [%@]", [bodyData length], bodyString);
	[bodyString release];

	[urlRequest setHTTPBody:bodyData];
	[bodyData release];

	[self connectWithRequest:[urlRequest autorelease]];
}





#pragma mark -

- (void)appendParamToBodyData:(NSMutableData*)postBodyData
					   andKey:(NSString*)key
					 andValue:(NSString*)value
{
	[postBodyData appendData:[[NSString stringWithFormat:@"--%@\r\n",
							   kMultipartBoundarySuffix] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
							  dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:[value dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
	//if (DEBUG) Me2Log(@"===> length : %@ >> %d", key, [postBodyData length]);
}


- (void)appendAttachToBodyData:(NSMutableData*)postBodyData
						andKey:(NSString*)key
					 andAttach:(Me2DayAttach*)attach
{
	[postBodyData appendData:[[NSString stringWithFormat:@"--%@\r\n",
							   kMultipartBoundarySuffix] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:[[NSString stringWithFormat:
							   @"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",
							   key, attach.fileName] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:[[NSString stringWithFormat:
							   @"Content-Type: %@\r\n\r\n" ,
							   attach.contentType] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBodyData appendData:attach.attachData];
	[postBodyData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
	//if (DEBUG) Me2Log(@"===> length : %@ >> %d", key, [postBodyData length]);
}

- (void)failMessage:(NSString*)message
		   andError:(NSError*)error
{
	[m_delegate me2dayRequest:self
			   didFailWithTag:m_me2dayTag
				  withMessage:message
					withError:error];

	[m_delegate me2dayRequest:self
			 didFinishWithTag:m_me2dayTag];
}


- (void)connectWithRequest:(NSURLRequest*)request
{
	NSURLConnection* urlConnection = [NSURLConnection connectionWithRequest:request delegate:self];
	//[request release];

	if (urlConnection == nil)
	{
		//if (DEBUG) Me2Log(@"===> yyy");
		[self failMessage:@"me2day request failed!!" andError:nil];
		return;
	}

	//if (DEBUG) Me2Log(@"===> zzz");
	if (m_responseData == nil)
	{
		m_responseData = [[NSMutableData data] retain];
	}
}






#pragma mark -
#pragma mark NSURLConnection delegate

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
	m_responseCode = [((NSHTTPURLResponse*)response) statusCode];
	//if (DEBUG) Me2Log(@"===> responseCode : %d", m_responseCode);
	if ((m_responseCode == 200 || m_responseCode == 500) ==  NO)
	{
		[self failMessage:@"me2day request failed!!" andError:nil];
		return;
	}

	if (m_responseData == nil)
	{
		m_responseData = [[NSMutableData data] retain];
	}
	[m_responseData setLength:0];
}


- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
	[m_responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
	if ((m_responseCode == 200 || m_responseCode == 500) == NO)
	{
		return;
	}

	if (m_responseData == nil || m_responseData.length == 0)
	{
		[self failMessage:@"me2day request failed!!" andError:nil];
		return;
	}

	//if (DEBUG) Me2Log(@"111 ----- bbb");
	//if (DEBUG) Me2Log(@"=====> responseData : %@", m_responseData);
	NSString* responseJSONString = [[NSString alloc] initWithData:m_responseData encoding:NSUTF8StringEncoding];
	if (m_responseData != nil)
	{
		[m_responseData release];
		m_responseData = nil;
	}

	//if (DEBUG) Me2Log(@"=====> responseJSONString : %@", responseJSONString);
	NSDictionary* responseDic = [responseJSONString JSONValue];
	//if (DEBUG) Me2Log(@"=====> responseDic : %@", responseDic);

	if (responseDic == nil || responseDic.count <= 0)
	{
		NSError* error = [[NSError alloc] initWithDomain:@"etcErrDomain"
													code:101
												userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
														  responseJSONString, NSLocalizedDescriptionKey,
														  nil]];
		[responseJSONString release];
		[self failMessage:@"me2day request failed!!" andError:[error autorelease]];
		return;
	}

	[responseJSONString release];
	if (m_responseCode == 200)
	{
		[m_delegate me2dayRequest:self
				didSuccessWithTag:m_me2dayTag
					   withResult:responseDic];

		[m_delegate me2dayRequest:self
				 didFinishWithTag:m_me2dayTag];
	}
	else
	{
		NSError* error = [[NSError alloc] initWithDomain:@"me2dayErrDomain"
													code:[[responseDic objectForKey:@"code"] intValue]
												userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
														  [NSString stringWithFormat:@"%@\n(%@)",
														   [responseDic objectForKey:@"description"],
														   [responseDic objectForKey:@"message"]], NSLocalizedDescriptionKey,
														  nil]];

		[self failMessage:[NSString stringWithFormat:@"me2day request failed!!\n%@",
						   [error localizedDescription]]
				 andError:[error autorelease]];
	}
}

- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
	[self failMessage:@"me2day request failed!!" andError:error];
}


@end
